home *** CD-ROM | disk | FTP | other *** search
- # Source Generated with Decompyle++
- # File: in.pyo (Python 2.5)
-
- from M2Crypto import util, EVP, m2
- import re
-
- class SSLVerificationError(Exception):
- pass
-
-
- class NoCertificate(SSLVerificationError):
- pass
-
-
- class WrongCertificate(SSLVerificationError):
- pass
-
-
- class WrongHost(SSLVerificationError):
-
- def __init__(self, expectedHost, actualHost, fieldName = 'commonName'):
- if fieldName not in ('commonName', 'subjectAltName'):
- raise ValueError('Unknown fieldName, should be either commonName or subjectAltName')
-
- SSLVerificationError.__init__(self)
- self.expectedHost = expectedHost
- self.actualHost = actualHost
- self.fieldName = fieldName
-
-
- def __str__(self):
- s = 'Peer certificate %s does not match host, expected %s, got %s' % (self.fieldName, self.expectedHost, self.actualHost)
- if isinstance(s, unicode):
- s = s.encode('utf8')
-
- return s
-
-
-
- class Checker:
- numericIpMatch = re.compile('^[0-9]+(\\.[0-9]+)*$')
-
- def __init__(self, host = None, peerCertHash = None, peerCertDigest = 'sha1'):
- self.host = host
- self.fingerprint = peerCertHash
- self.digest = peerCertDigest
-
-
- def __call__(self, peerCert, host = None):
- if peerCert is None:
- raise NoCertificate('peer did not return certificate')
-
- if host is not None:
- self.host = host
-
- if self.fingerprint:
- if self.digest not in ('sha1', 'md5'):
- raise ValueError('unsupported digest "%s"' % self.digest)
-
- if (self.digest == 'sha1' or len(self.fingerprint) != 40 or self.digest == 'md5') and len(self.fingerprint) != 32:
- raise WrongCertificate('peer certificate fingerprint length does not match')
-
- der = peerCert.as_der()
- md = EVP.MessageDigest(self.digest)
- md.update(der)
- digest = md.final()
- if util.octx_to_num(digest) != int(self.fingerprint, 16):
- raise WrongCertificate('peer certificate fingerprint does not match')
-
-
- if self.host:
- hostValidationPassed = False
- self.useSubjectAltNameOnly = False
-
- try:
- subjectAltName = peerCert.get_ext('subjectAltName').get_value()
- if not self._splitSubjectAltName(self.host, subjectAltName):
- raise WrongHost(expectedHost = self.host, actualHost = subjectAltName, fieldName = 'subjectAltName')
-
- hostValidationPassed = True
- except LookupError:
- pass
-
- if not (self.useSubjectAltNameOnly) and not hostValidationPassed:
- hasCommonName = False
- commonNames = ''
- for entry in peerCert.get_subject().get_entries_by_nid(m2.NID_commonName):
- hasCommonName = True
- commonName = entry.get_data().as_text()
- if not commonNames:
- commonNames = commonName
- else:
- commonNames += ',' + commonName
- if self._match(self.host, commonName):
- hostValidationPassed = True
- break
- continue
-
- if not hasCommonName:
- raise WrongCertificate('no commonName in peer certificate')
-
- if not hostValidationPassed:
- raise WrongHost(expectedHost = self.host, actualHost = commonNames, fieldName = 'commonName')
-
-
-
- return True
-
-
- def _splitSubjectAltName(self, host, subjectAltName):
- self.useSubjectAltNameOnly = False
- for certHost in subjectAltName.split(','):
- certHost = certHost.lower().strip()
- if certHost[:4] == 'dns:':
- self.useSubjectAltNameOnly = True
- if self._match(host, certHost[4:]):
- return True
-
- self._match(host, certHost[4:])
-
- return False
-
-
- def _match(self, host, certHost):
- host = host.lower()
- certHost = certHost.lower()
- if host == certHost:
- return True
-
- if certHost.count('*') > 1:
- return False
-
- if self.numericIpMatch.match(host) or self.numericIpMatch.match(certHost.replace('*', '')):
- return False
-
- if certHost.find('\\') > -1:
- return False
-
- certHost = certHost.replace('.', '\\.')
- certHost = certHost.replace('*', '[^\\.]*')
- if re.compile('^%s$' % certHost).match(host):
- return True
-
- return False
-
-
- if __name__ == '__main__':
- import doctest
- doctest.testmod()
-
-